www.gusucode.com > VC++ 三维图形生成和察看工具 > VC++ 三维图形生成和察看工具/code/mesh/Lib3D/Vertex3d.cpp

    //Download by http://www.NewXing.com
//********************************************
// Vertex3d.cpp
//********************************************
// class CVertex3d
//********************************************
// alliez@usc.edu
// Created : 10/12/97
// Modified : 14/01/98
//********************************************

#include "stdafx.h"
#include "math.h"

#include "Base3d.h"
#include "Vertex3d.h"
#include "Face3d.h"

//////////////////////////////////////////////
// DATAS
//////////////////////////////////////////////

//********************************************
// GetType
//********************************************
int CVertex3d::GetType()
{
	return TYPE_VERTEX3D;
}



//////////////////////////////////////////////
// OPERATORS
//////////////////////////////////////////////

//********************************************
// Operator = 
//********************************************
CVertex3d CVertex3d::operator=(CVertex3d& vertex)
{
	CVertex3d v;
	v.Set(vertex);
	return v;
}


//////////////////////////////////////////////
// VERTEX NEIGHBORING
//////////////////////////////////////////////

//********************************************
// AddNeighbor
//********************************************
void CVertex3d::AddNeighbor(CVertex3d *pVertex)
{
	// Duplicate vertices are removed
	if(pVertex == this)
		return;

	if(!HasNeighbor(pVertex))
		m_ArrayVertexNeighbor.Add(pVertex);
}

//********************************************
// AddNeighborNoCheck
//********************************************
void CVertex3d::AddNeighborNoCheck(CVertex3d *pVertex)
{
	// Add a neighboring vertex
	m_ArrayVertexNeighbor.Add(pVertex);
}


//********************************************
// NbNeighbor
//********************************************
int CVertex3d::NbVertexNeighbor(void)
{
	return m_ArrayVertexNeighbor.GetSize();
}

//********************************************
// RemoveAllNeighbor
//********************************************
void CVertex3d::RemoveAllVertexNeighbor(void)
{
	m_ArrayVertexNeighbor.RemoveAll();
}

//********************************************
// RemoveVertexNeighbor
//********************************************
int CVertex3d::RemoveNeighbor(CVertex3d *pVertex)
{
	int size = m_ArrayVertexNeighbor.GetSize();
	for(int i=0;i<size;i++)
		if(m_ArrayVertexNeighbor[i]==pVertex)
		{
			m_ArrayVertexNeighbor.RemoveAt(i);
			return 1;
		}
	return 0;
}

//********************************************
// UpdateNeighbor
//********************************************
int CVertex3d::UpdateNeighbor(CVertex3d *pVertexOld,
															CVertex3d *pVertexNew)
{
	int success = 0;
	for(int j=0;j<m_ArrayVertexNeighbor.GetSize();j++)
		if(m_ArrayVertexNeighbor[j] == pVertexOld)
		{
			m_ArrayVertexNeighbor.RemoveAt(j);
			this->AddNeighbor(pVertexNew);
			pVertexNew->AddNeighbor(this);
			success = 1;
		}
	return success;
}

//********************************************
// UpdateNeighbor
//********************************************
void CVertex3d::UpdateNeighborRecursive(CVertex3d *pVertexOld,
																				CVertex3d *pVertexNew)
{
	for(int i=0;i<m_ArrayVertexNeighbor.GetSize();i++)
		if(m_ArrayVertexNeighbor[i]!=NULL)
			m_ArrayVertexNeighbor[i]->UpdateNeighbor(pVertexOld,pVertexNew);
}

//********************************************
// FindFaceAroundContainVertex
//********************************************
int CVertex3d::FindFaceAroundContainVertex(CVertex3d *pVertex,
																					 CArray3d<CFace3d> &ArrayFace)
{
	int success = 0;
	for(int i=0;i<m_ArrayFaceNeighbor.GetSize();i++)
		if(m_ArrayFaceNeighbor[i] != NULL)
			if(m_ArrayFaceNeighbor[i]->HasVertex(pVertex))
			{
				ArrayFace.Add(m_ArrayFaceNeighbor[i]);
				success = 1;
			}
	return success;
}


//********************************************
// GetMeanAreaAround
//********************************************
double CVertex3d::GetMeanAreaAround()
{
	return ::GetMeanArea(&m_ArrayFaceNeighbor);
}

//********************************************
// GetMinAreaAround
//********************************************
double CVertex3d::GetMinAreaAround()
{
	return ::GetMinArea(&m_ArrayFaceNeighbor);
}

//////////////////////////////////////////////
// FACE NEIGHBORING
//////////////////////////////////////////////

//********************************************
// AddFaceNeighbor
//********************************************
void CVertex3d::AddNeighbor(CFace3d *pFace)
{
	// Add a neighboring face only when it
	// is not included in the array
	if(!HasNeighbor(pFace))
		m_ArrayFaceNeighbor.Add(pFace);
}


//********************************************
// NbFaceNeighbor
//********************************************
int CVertex3d::NbFaceNeighbor(void)
{
	return m_ArrayFaceNeighbor.GetSize();
}

//********************************************
// RemoveAllFaceNeighbor
//********************************************
void CVertex3d::RemoveAllFaceNeighbor(void)
{
	m_ArrayFaceNeighbor.RemoveAll();
}

//********************************************
// RemoveFaceNeighbor
//********************************************
int CVertex3d::RemoveNeighbor(CFace3d *pFace)
{
	int size = m_ArrayFaceNeighbor.GetSize();
	for(int i=0;i<size;i++)
		if(m_ArrayFaceNeighbor[i]==pFace)
		{
			m_ArrayFaceNeighbor.RemoveAt(i);
			return 1;
		}
	return 0;
}

//********************************************
// Find each faces sharing between pVertex
// and "this"
// We assume adjacency is built
//********************************************
int CVertex3d::FindSharingFaces(CVertex3d *pVertex,
															  CArray3d<CFace3d> &array)
{
	int added = 0;
	int NbFaceNeighbor = pVertex->NbFaceNeighbor();
	for(int i=0;i<NbFaceNeighbor;i++)
	{
		if(m_ArrayFaceNeighbor.Has(pVertex->GetFaceNeighbor(i)))
		{
			array.Add(pVertex->GetFaceNeighbor(i));
			added++;
		}
	}
	return added;
}


//////////////////////////////////////////////
// BOUNDARIES
//////////////////////////////////////////////


//********************************************
// IsOnBoundary
//********************************************
int CVertex3d::IsOnBoundary()
{
	// ** DEBUG **
	int size = m_ArrayFaceNeighbor.GetSize();
	for(int i=0;i<size;i++)
		for(int j=0;j<3;j++)
			if(m_ArrayFaceNeighbor[i]->f(j) == NULL && 
				 (m_ArrayFaceNeighbor[i]->v(j) == this || 
				  m_ArrayFaceNeighbor[i]->v((j+1)%3) == this))
				return 1;
	return 0;
}

//////////////////////////////////////////////
// FLAGS
//////////////////////////////////////////////

int CVertex3d::HasNeighborWithFlag(int flag)
{
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex->GetFlag() == flag)
			return 1;
	}
	return 0;
}

int CVertex3d::HasNeighborWithFlagButDiff(int flag,
																					CVertex3d *pVertexDiff)
{
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex != pVertexDiff)
			if(pVertex->GetFlag() == flag)
				return 1;
	}
	return 0;
}



CVertex3d *CVertex3d::GetFirstVertexNeighborWithFlag(int flag)
{
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex->GetFlag() == flag)
			return pVertex;
	}
	return NULL;
}

CVertex3d *CVertex3d::GetNearestVertexNeighborWithFlag(int flag)
{
	double distance = 1e38;
	CVertex3d *pVertexNearest = NULL;
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex->GetFlag() == flag)
		{
			double tmp = ::DistanceSquare(this,pVertex);
			if(tmp < distance)
			{
				pVertexNearest = pVertex;
				distance = tmp;
			}
		}

	}
	return pVertexNearest;
}


int CVertex3d::DiffFlagsOnNeighboringFaces()
{
	int size = NbFaceNeighbor();
	if(size <= 1)
		return 0;

	int flag = m_ArrayFaceNeighbor[0]->GetFlag(); // first flag
	for(int i=1;i<size;i++)
	{
		CFace3d *pFace = m_ArrayFaceNeighbor[i];
		int tmp = pFace->GetFlag();
		if(tmp != flag)
			return 1;
	}
	return 0;
}


int CVertex3d::IsFlagSmallestOnNeighboringFaces(int flag)
{
	int size = NbFaceNeighbor();
	for(int i=0;i<size;i++)
	{
		CFace3d *pFace = m_ArrayFaceNeighbor[i];
		int tmp = pFace->GetFlag();
		if(tmp < flag)
			return 0;
	}
	return 1;
}


CVertex3d *CVertex3d::GetFirstVertexNeighborWithFlagButDiff(int flag,
																														CVertex3d *pVertexDiff)
{
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex != pVertexDiff)
			if(pVertex->GetFlag() == flag)
				return pVertex;
	}
	return NULL;
}


int CVertex3d::NbVertexNeighborWithFlag(int flag)
{
	int nb = 0;
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
		if(m_ArrayVertexNeighbor[i]->GetFlag() == flag)
			nb++;
	return nb;
}

int CVertex3d::FindVertexNeighborsWhichFlagIsGreater(int flag,
																										 CArray3d<CVertex3d> &array)
{
	int added = 0;
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex->GetFlag() > flag)
		{
			array.Add(pVertex);
			added++;
		}
	}
	return added;
}

int CVertex3d::FindVertexNeighborsWhichFlagIsSmaller(int flag,
																										 CArray3d<CVertex3d> &array)
{
	int added = 0;
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex->GetFlag() < flag)
		{
			array.Add(pVertex);
			added++;
		}
	}
	return added;
}

//********************************************
// 	GetFirstNeighborWithFlagAndSharingFaceWithFlag
//********************************************
CVertex3d *CVertex3d::GetFirstNeighborWithFlagAndSharingFaceWithFlag(int FlagVertex,
																																		 int FlagFace)
{
	int size = NbVertexNeighbor();
	for(int i=0;i<size;i++)
	{
		CVertex3d *pVertex = m_ArrayVertexNeighbor[i];
		if(pVertex->GetFlag() == FlagVertex)
		{
			CArray3d<CFace3d> array;
			if(FindSharingFaces(pVertex,array))
			{
				int NbFace = array.GetSize();
				for(int j=0;j<NbFace;j++)
				{
					CFace3d *pFace = array[j];
					if(pFace->GetFlag() == FlagFace)
						return pVertex;
				}
			}
		}
	}
	return NULL;
}




//////////////////////////////////////////////
// SHARP EDGES
//////////////////////////////////////////////

//********************************************
// NbSharpEdge
//********************************************
int CVertex3d::NbSharpEdge(const double threshold)
{
	// 3 sharp edges on boundaries
	if(IsOnBoundary())
		return 3;
	int NbSharp = ::NbSharpEdge(m_ArrayFaceNeighbor,threshold);
	//TRACE("NbSharp : %d\n",NbSharp);
	return NbSharp;
}

//********************************************
// 	NormalSum
//********************************************
int CVertex3d::NormalSum(double *pSum)
{
	return ::NormalSum(m_ArrayFaceNeighbor,pSum);
}

//********************************************
// 	NormalMax
//********************************************
int CVertex3d::NormalMax(double *pMax)
{
	return ::NormalMax(m_ArrayFaceNeighbor,pMax);
}


//////////////////////////////////////////////
//////////////////////////////////////////////
// CURVENESS
//////////////////////////////////////////////
//////////////////////////////////////////////

//********************************************
// GetMeanCurveAround
//********************************************
double CVertex3d::GetMeanCurveAround()
{
	int size = m_ArrayFaceNeighbor.GetSize();
	if(size == 0)
		return 0.0f;
	double sum;
	::NormalSum(m_ArrayFaceNeighbor,&sum);
	return sum/size;
}

//********************************************
// GetSumCurveAround
//********************************************
double CVertex3d::GetSumCurveAround()
{
	double sum;
	if(::NormalSum(m_ArrayFaceNeighbor,&sum))
		return sum;
	else
		return 0.0;
}

//********************************************
// GetMaxCurveAround
//********************************************
double CVertex3d::GetMaxCurveAround()
{
	double max;
	if(::NormalMax(m_ArrayFaceNeighbor,&max))
		return max;
	else
	{
		TRACE("** CVertex3d::GetMaxCurveAround\n");
		return 0.0;
	}
}

double CVertex3d::GetMaxAngleAround()
{
	double max;
	if(::MaxAngleBetweenFaces(m_ArrayFaceNeighbor,&max))
		return max;
	else
		return 0.0;
}


//********************************************
// GetMaxCurveAroundAndNeighbors
//********************************************
double CVertex3d::GetMaxCurveAroundAndNeighbors()
{
	double max = 0.0;
	::NormalMax(m_ArrayFaceNeighbor,&max);
	int size = m_ArrayVertexNeighbor.GetSize();
	for(int i=0;i<size;i++)
		max = max(max,m_ArrayVertexNeighbor[i]->GetMaxCurveAround());
	return max;
}




//////////////////////////////////////////////
// MISC
//////////////////////////////////////////////

//********************************************
// Diff
//********************************************
int CVertex3d::Diff(CVertex3d *pVertex)
{
	return ( (m_Coord[0] != pVertex->x()) || 
		       (m_Coord[1] != pVertex->y()) || 
					 (m_Coord[2] != pVertex->z()));
}

//********************************************
// Equal
//********************************************
int CVertex3d::Equal(CVertex3d *pVertex)
{
	return ( (m_Coord[0] == pVertex->x()) && 
		       (m_Coord[1] == pVertex->y()) && 
					 (m_Coord[2] == pVertex->z()));
}


//////////////////////////////////////////////
// PRECISION
//////////////////////////////////////////////

//********************************************
// ReplaceOnGrid
//********************************************
void CVertex3d::ReplaceOnGrid(float threshold)
{
	for(int i=0;i<3;i++)
		m_Coord[i] = (m_Coord[i] < threshold) ? 0.0f : m_Coord[i];
}


//********************************************
// GetMeanLengthEdgeAround
//********************************************
double CVertex3d::GetMeanLengthEdgeAround()
{
	double sum = 0.0f;
	int size = m_ArrayVertexNeighbor.GetSize();
	if(size == 0)
		return 0.0f;

	for(int i=0;i<size;i++)
		sum += ::Distance(m_ArrayVertexNeighbor[i],this);

	return (sum/size);
}




//////////////////////////////////////////////
// DEBUG
//////////////////////////////////////////////

//********************************************
// Trace
//********************************************
void CVertex3d::Trace()
{
	TRACE("\n");
	TRACE("** Vertex **\n");
	TRACE("Adress      : %x\n",this);
	TRACE("Coordinates : (%g %g %g)\n",m_Coord[0],m_Coord[1],m_Coord[2]);
	TRACE("Normal      : (%g %g %g)\n",m_Normal.x(),m_Normal.y(),m_Normal.z());
	TRACE("Neighbors   : %d\n",m_ArrayVertexNeighbor.GetSize());
	int size = m_ArrayFaceNeighbor.GetSize();
	for(int i=0;i<size;i++)
	{
		m_ArrayFaceNeighbor[i]->Trace();
		ASSERT(m_ArrayFaceNeighbor[i]->IsValid());
	}
}


//////////////////////////////////////////////
// OPENGL
//////////////////////////////////////////////

//********************************************
// glDrawHighlight
// Highlights vertex and its neighbors
//********************************************
void CVertex3d::glDrawHighlight(const float radius,
																const float RadiusNeighbor,
																unsigned char *ColorVertex,
																CMesh3d *pMesh /* = NULL */,
																unsigned char *ColorNeightbor /* = NULL */)
{
	GLUquadricObj* pQuadric = gluNewQuadric();


	// Transform
	if(pMesh != NULL)
		{
			CTransform *pTransform = pMesh->GetTransform();
		::glPushMatrix();

			// Position / translation / scaling
			glTranslatef(pTransform->GetTranslation()->x(),
									 pTransform->GetTranslation()->y(),
									 pTransform->GetTranslation()->z());

			glScalef(pTransform->GetScale()->x(),
							 pTransform->GetScale()->y(),
							 pTransform->GetScale()->z());

			glRotatef(pTransform->GetValueRotation(),
								pTransform->GetRotation()->x(),
								pTransform->GetRotation()->y(),
								pTransform->GetRotation()->z());
		}

	// Main vertex
	glColor3ub(ColorVertex[0],ColorVertex[1],ColorVertex[2]);
	glPushMatrix();
	glTranslated(m_Coord[0],m_Coord[1],m_Coord[2]);
	gluSphere(pQuadric,radius,8,8); 
	glPopMatrix();

	// Neighbors
	if(ColorNeightbor != NULL)
		{
		int size = NbVertexNeighbor();
		if(size != 0)
			{
			glColor3ub(ColorNeightbor[0],ColorNeightbor[1],ColorNeightbor[2]);
			for(int i=0;i<size;i++)
				{
				CVertex3d *pVertex = (CVertex3d *)m_ArrayVertexNeighbor[i];
				glPushMatrix();
				glTranslated(pVertex->x(),pVertex->y(),pVertex->z());
				gluSphere(pQuadric,RadiusNeighbor,8,8); 
				glPopMatrix();
				}
			}
		}

	// Face neighbors
	int size = NbFaceNeighbor();
	if(size != 0)
		{
		glColor3ub(0,0,255);
		for(int i=0;i<size;i++)
			{
			CFace3d *pFace = m_ArrayFaceNeighbor[i];
			::glBegin(GL_TRIANGLES);
				::glVertex3f(pFace->v1()->x(),pFace->v1()->y(),pFace->v1()->z());
				::glVertex3f(pFace->v2()->x(),pFace->v2()->y(),pFace->v2()->z());
				::glVertex3f(pFace->v3()->x(),pFace->v3()->y(),pFace->v3()->z());
			::glEnd();
			}
		}

	// Restore
	if(pMesh != NULL)
		::glPopMatrix();

}

//********************************************
// glDraw
//********************************************
int CVertex3d::glDraw()
{
	GLUquadricObj* pQuadric = gluNewQuadric();

	// Main vertex
	glColor3ub(m_Color.r(),m_Color.g(),m_Color.b());
	glPushMatrix();
	glTranslated(m_Coord[0],m_Coord[1],m_Coord[2]);
	gluSphere(pQuadric,0.01,8,8); 
	glPopMatrix();
	return 1;
}

//********************************************
// glDraw
//********************************************
void CVertex3d::glDraw(const float radius,
											 unsigned char *ColorVertex,
											 CMesh3d *pMesh /* = NULL */)
{
	GLUquadricObj* pQuadric = gluNewQuadric();

	// Transform
	if(pMesh != NULL)
		{
			CTransform *pTransform = pMesh->GetTransform();
		::glPushMatrix();

			// Position / translation / scaling
			glTranslatef(pTransform->GetTranslation()->x(),
									 pTransform->GetTranslation()->y(),
									 pTransform->GetTranslation()->z());

			glScalef(pTransform->GetScale()->x(),
							 pTransform->GetScale()->y(),
							 pTransform->GetScale()->z());

			glRotatef(pTransform->GetValueRotation(),
								pTransform->GetRotation()->x(),
								pTransform->GetRotation()->y(),
								pTransform->GetRotation()->z());
		}

	// Main vertex
	glColor3ub(ColorVertex[0],ColorVertex[1],ColorVertex[2]);
	glPushMatrix();
	glTranslated(m_Coord[0],m_Coord[1],m_Coord[2]);
	gluSphere(pQuadric,radius,8,8); 
	gluDeleteQuadric(pQuadric);
	glPopMatrix();

	// Restore
	if(pMesh != NULL)
		::glPopMatrix();
}




// ** EOF **